import Vector from "../vector";
import type { Coord } from "../../types";

/**
 * @description 矩阵类
 * @author hzq
 * @date 2025-04-11 20:28:38
 * @copyright Copyright (c) 2025 by hzq, All Rights Reserved.
 */
class Metrix {
  // 定义一个二维数组
  private _data: number[][];

  // 构造函数，传入一个二维数组
  constructor(data: number[][]) {
    this._data = data;
  }

  // 获取矩阵的形状
  private get shape() {
    return [this._data.length, this._data[0].length];
  }

  /**
   * #### 获取矩阵的行数
   */
  get row() {
    return this.shape[0];
  }

  /**
   * #### 获取矩阵的列数
   */
  get col() {
    return this.shape[1];
  }

  /**
   * #### 获取矩阵的大小
   * @returns
   */
  size() {
    return this.row * this.col;
  }

  /**
   * #### 获取指定行的向量
   * @param index 指定行数
   * @returns
   */
  rowVector(index: number) {
    return new Vector(...this._data[index]);
  }

  /**
   * #### 获取指定列的向量
   * @param index 指定列数
   * @returns
   */
  colVector(index: number) {
    return new Vector(...this._data.map((row) => row[index]));
  }

  /**
   * #### 获取指定坐标的元素
   * @param coord 指定坐标
   * @returns
   */
  getItem(coord: Coord) {
    return this._data[coord[0]][coord[1]];
  }

  /**
   * #### 设置指定坐标的元素
   * @param coord 指定坐标
   * @param value
   * @returns
   */
  setItem(coord: Coord, value: number) {
    this._data[coord[0]][coord[1]] = value;
    return this;
  }

  /**
   * #### 矩阵乘以一个数
   * @param k 乘数
   * @returns
   */
  mul(k: number) {
    return new Metrix(this._data.map((row) => row.map((item) => item * k)));
  }

  /**
   * #### 矩阵除以一个数
   * @param k 除数
   * @returns
   */
  div(k: number) {
    if (!k) throw new Error("Divided by zero");
    return this.mul(1 / k);
  }

  /**
   * #### 矩阵取正
   * @returns
   */
  pos() {
    return this.mul(1);
  }

  /**
   * #### 矩阵取负
   * @returns
   */
  neg() {
    return this.mul(-1);
  }

  /**
   * #### 两矩阵相加
   * @param another 另一个矩阵
   * @returns
   */
  add(another: Metrix) {
    if (
      this.shape[0] !== another.shape[0] ||
      this.shape[1] !== another.shape[1]
    ) {
      throw new Error("Matrix shape not match");
    }
    return new Metrix(
      this._data.map((row, i) =>
        row.map((item, j) => item + another.getItem([i, j]))
      )
    );
  }

  /**
   * #### 两矩阵相减
   * @param another 另一个矩阵
   * @returns
   */
  sub(another: Metrix) {
    return this.add(another.neg());
  }

  /**
   * #### 矩阵乘以一个向量
   * @param vector 向量
   * @returns
   */
  mulVector(vector: Vector) {
    if (this.col !== vector.dimension) {
      throw new Error("Matrix shape not match");
    }
    return new Metrix(
      this._data.map((row) => row.map((item, i) => item * vector.getItem(i)))
    );
  }

  /**
   * #### 矩阵乘以另一个矩阵
   * @param another 另一个矩阵
   * @returns
   */
  mulMetrix(another: Metrix) {
    if (this.col !== another.row) {
      throw new Error("Matrix shape not match");
    }
    const result = Metrix.zero(this.row, another.col);
    for (let i = 0; i < this.row; i++) {
      const rowList = this.rowVector(i);
      for (let j = 0; j < this.col; j++) {
        result.setItem([i, j], rowList.dot(another.colVector(j)));
      }
    }
    return result;
  }

  /**
   * #### 创建一个全零矩阵
   * @static
   * @param row 行数
   * @param col 列数
   * @returns
   */
  static zero(row: number, col: number) {
    return new Metrix(
      Array.from({ length: row }, () => Array.from({ length: col }, () => 0))
    );
  }

  /**
   * #### 将矩阵转换为字符串
   * @returns
   */
  toString() {
    return this._data.map((row) => row.join(" ")).join("\n");
  }
}

export default Metrix;
